package cn.edu.xmu.oomall.customer.dao;


import cn.edu.xmu.javaee.core.exception.BusinessException;
import cn.edu.xmu.javaee.core.mapper.RedisUtil;
import cn.edu.xmu.javaee.core.model.ReturnNo;
import cn.edu.xmu.javaee.core.model.dto.UserDto;
import cn.edu.xmu.javaee.core.util.CloneFactory;
import cn.edu.xmu.oomall.customer.dao.bo.Address;
import cn.edu.xmu.oomall.customer.dao.openfegin.RegionDao;
import cn.edu.xmu.oomall.customer.mapper.AddressPoMapper;
import cn.edu.xmu.oomall.customer.mapper.po.AddressPo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Repository
@RefreshScope
@RequiredArgsConstructor
public class AddressDao {

    private final static Logger logger = LoggerFactory.getLogger(AddressDao.class);

    private final static String KEY = "A%d";

    @Value("${oomall.region.timeout}")
    private int timeout;

    private final AddressPoMapper addressPoMapper;

    private final RedisUtil redisUtil;

    public Address build(Address bo) {
        bo.setAddressDao(this);
        return bo;
    }

    public Address build(AddressPo po, Optional<String> redisKey) {
        Address bo = CloneFactory.copy(new Address(), po);
        this.build(bo);
        redisKey.ifPresent(key -> redisUtil.set(key, bo, timeout));
        return bo;
    }


    public Address findById(Long addressId) {
        logger.debug("findById: id = {}", addressId);
        assert (!Objects.isNull(addressId)) : "id can not be null";
        String key = String.format(KEY, addressId);
        Address bo = (Address) redisUtil.get(key);
        if (Objects.isNull(bo)) {
            // 缓存中没有
            Optional<AddressPo> ret = addressPoMapper.findById(addressId);
            if (ret.isPresent()) {
                logger.debug("findById: retrieve from database address = {}", ret.get());
                return this.build(ret.get(), Optional.of(key));
            } else {
                throw new BusinessException(ReturnNo.RESOURCE_ID_NOTEXIST, String.format(ReturnNo.RESOURCE_ID_NOTEXIST.getMessage(), "地址", addressId));
            }
        } else {
            logger.debug("findById: hit in redis key = {}, address = {}", key, bo);
            this.build(bo);
            return bo;
        }
    }

    public void save(Address bo, UserDto user) {
        bo.setModifier(user);
        bo.setGmtModified(LocalDateTime.now());
        AddressPo po = CloneFactory.copy(new AddressPo(), bo);
        addressPoMapper.save(po);
        logger.debug("save: po = {}", po);
    }

    public Address findByBeDefault(Byte isDefault) {
        List<AddressPo> po = addressPoMapper.findByBeDefault(isDefault);
        Address bo = CloneFactory.copy(new Address(), po.get(0));
        return bo;
    }

    public List<Address> retrieveAddress(UserDto user, Integer page, Integer pageSize) {
        Pageable pageable = PageRequest.of(page - 1, pageSize);
        user.setId(13L);
        List<AddressPo> pos = this.addressPoMapper.findByCustomerId(user.getId(), pageable);
        return pos.stream().map(po -> {
            Address bo = CloneFactory.copy(new Address(), po);
            bo = build(bo);
            return bo;
        }).collect(Collectors.toList());
    }

    public void delAddress(Long addressId, UserDto user) {
        addressPoMapper.deleteById(addressId);
    }
}
